package be.rivendale.renderer;

import be.rivendale.renderer.mk2.data.Frame;
import be.rivendale.renderer.mk2.data.Rectangle;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Renderer {
    private ThreadPoolExecutor executorService;
    private RenderingWindow window;

    public Renderer(int numberOfConcurrentRenderingThreads) {
        window = new RenderingWindow(RenderTask.info.getHorizontalCameraResolution(), RenderTask.info.getVerticalCameraResolution(), false);
        executorService = new ThreadPoolExecutor(numberOfConcurrentRenderingThreads, numberOfConcurrentRenderingThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()) {
            @Override
            protected void afterExecute(Runnable runnable, Throwable throwable) {
                try {
                    FutureTask<ScreenPart> task = (FutureTask<ScreenPart>) runnable;
                    ScreenPart screenPart = task.get();
                    window.drawToBackBuffer(screenPart);
                    window.flipBuffers();
                } catch (Exception exception) {
					throw new RuntimeException("Unable to render screen part", exception);
                }
            }
        };
    }

    public void start() {
		long startTime = System.nanoTime();
		renderFrame();
		long endTime = System.nanoTime();
		long totalTimeInMilliseconds = (endTime - startTime) / 1000000;
		System.out.format("%dms (%.2ffps)\n", totalTimeInMilliseconds, (1000.0 / totalTimeInMilliseconds));
    }

    private void renderFrame() {
        try {
            executorService.invokeAll(createRenderingTasks());
        } catch (InterruptedException exception) {
            throw new RuntimeException(exception);
        }
    }

    private List<RenderTask> createRenderingTasks() {
        List<Rectangle> rectangles = new Frame().createSegments();
        ArrayList<RenderTask> renderTasks = new ArrayList<RenderTask>();
        for (Rectangle rectangle : rectangles) {
            renderTasks.add(new RenderTask(rectangle));
        }
        return renderTasks;
    }
}
